/*
 * LineNumberPane.java
 */

package xq.swing;

import xq.swing.borders.LineBorder;
import java.awt.Insets;
import java.awt.Rectangle;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.event.DocumentEvent;
import javax.swing.text.JTextComponent;
import xq.swing.text.DocumentAdapter;

/**
 *
 * @author ThorntonRP
 */
public class LineNumberPane extends JScrollPane {

	private static final long serialVersionUID = -4272540448604672618L;
	
	private JTextComponent lineNumberTextComponent;
	private Insets borderInsets;
	private int lineCount;

	public LineNumberPane() {
		borderInsets = new Insets(0, 0, 0, 1);
		initComponents();
	}

	public void bindTo(final JTextComponent textComponent) {
		textComponent.addPropertyChangeListener("border", new PropertyChangeListener() {
			@Override
			public void propertyChange(PropertyChangeEvent evt) {
				updateBorder(textComponent);
			}
		});
		textComponent.addPropertyChangeListener("margin", new PropertyChangeListener() {
			@Override
			public void propertyChange(PropertyChangeEvent evt) {
				updateBorder(textComponent);
			}
		});
		textComponent.addPropertyChangeListener("font", new PropertyChangeListener() {
			@Override
			public void propertyChange(PropertyChangeEvent evt) {
				lineNumberTextComponent.setFont(textComponent.getFont());
			}
		});
		textComponent.getDocument().addDocumentListener(new DocumentAdapter() {
			@Override
			public void update(DocumentEvent e) {
				updateLineNumbers(textComponent);
			}
		});
		textComponent.addPropertyChangeListener("document", new PropertyChangeListener() {
			@Override
			public void propertyChange(PropertyChangeEvent evt) {
				textComponent.getDocument().addDocumentListener(new DocumentAdapter() {
					@Override
					public void update(DocumentEvent e) {
						updateLineNumbers(textComponent);
					}
				});
				updateLineNumbers(textComponent);
			}
		});

		lineNumberTextComponent.setFont(textComponent.getFont());
		updateBorder(textComponent);
		updateLineNumbers(textComponent);
	}

	private void updateBorder(JTextComponent textComponent) {
		Insets margin = lineNumberTextComponent.getMargin();
		Insets insets;
		if (textComponent == null) {
			insets = lineNumberTextComponent.getMargin();
		} else if (textComponent.getBorder() != null) {
			insets = textComponent.getBorder().getBorderInsets(textComponent);
		} else {
			insets = new Insets(0, 0, 0, 0);
		}
		margin.top = insets.top - borderInsets.top;
		margin.bottom = insets.bottom - borderInsets.bottom;
		lineNumberTextComponent.setMargin(margin);
		lineNumberTextComponent.setBorder(createBorder());
	}

	private Border createBorder() {
		return new LineBorder(
				UIManager.getColor("controlShadow"),
				borderInsets,
				lineNumberTextComponent.getMargin());
	}

	private void updateLineNumbers(JTextComponent textComponent) {
		int newLineCount = getLineCount(textComponent);
		if (newLineCount != lineCount) {
			lineCount = newLineCount;
			String lineNumbers = getLineNumbers(newLineCount);
			lineNumberTextComponent.setText(lineNumbers);
			if (getParent() != null) {
				getParent().validate();
			}
		}
	}

	private void initComponents() {
		lineNumberTextComponent = new TextPaneImpl();
		lineNumberTextComponent.setEditable(false);
		lineNumberTextComponent.setFocusable(false);
		lineNumberTextComponent.setBackground(UIManager.getColor("control"));
		lineNumberTextComponent.setForeground(UIManager.getColor("controlText"));
		lineNumberTextComponent.setMargin(new Insets(0, 10, 0, 3));
		lineNumberTextComponent.setBorder(createBorder());

		setBorder(null);
		setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_NEVER);
		setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_NEVER);
		getViewport().setView(lineNumberTextComponent);
	}

	private static int getLineCount(JTextComponent textComponent) {
		String text = textComponent.getText();
		int lineCount = 1;
		int index = -1;
		while ((index = text.indexOf('\n', index + 1)) != -1) {
			lineCount++;
		}
		return lineCount;
	}

	private static String getLineNumbers(int lineCount) {
		int charWidth = String.valueOf(lineCount).length();
		StringBuilder sb = new StringBuilder();
		for (int i = 1; i <= lineCount; i++) {
			if (i > 1) {
				sb.append('\n');
			}
			String n = String.valueOf(i);
			for (int j = n.length(); j < charWidth; j++) {
				sb.append(' ');
			}
			sb.append(n);
		}
		return sb.toString();
	}

	private class TextPaneImpl extends JTextPane {

		private static final long serialVersionUID = -8942961096907512536L;

		@Override
		public void scrollRectToVisible(Rectangle aRect) {
			// Don't scroll
		}
	}
}
